﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using QuanserClient;
using TankController.Dominio;

namespace TankController
{
    public partial class FormConfigurarTipoA : FormConfigurar, IFormConfigurar
    {
        private IControlador controlador;
        private ControladorMalhaAberta controladorMA;
        private ControladorMalhaFechada controladorMF;
        private IEntrada entrada;

        public FormConfigurarTipoA(FormPrincipal formPrincipal)
        {
            InitializeComponent();
        
            this.formPrincipal = formPrincipal;

            MontarTiposControlador();
        }

        private void FormConfigurar_Shown(object sender, EventArgs e)
        {
            if (Global.Controlador1 != null)
            {
                btnCancelar.Enabled = true;

                if (Global.Controlador1 is ControladorMalhaAberta || Global.Controlador1 is ControladorMalhaFechada)
                {
                    AtualizarCampos();
                }
            }
            else
            {
                btnCancelar.Enabled = false;
            }
        }

        private void MontarTiposControlador()
        {
            ArrayList tiposControlador = new ArrayList();

            tiposControlador.Add(new { Valor = TipoControlador.PadraoMA, Descricao = "Malha Aberta" });
            tiposControlador.Add(new { Valor = TipoControlador.PadraoMF, Descricao = "Malha Fechada" });
            tiposControlador.Add(new { Valor = TipoControlador.P, Descricao = "Controlador P" });
            tiposControlador.Add(new { Valor = TipoControlador.PI, Descricao = "Controlador PI" });
            tiposControlador.Add(new { Valor = TipoControlador.PD, Descricao = "Controlador PD" });
            tiposControlador.Add(new { Valor = TipoControlador.PID, Descricao = "Controlador PID" });
            tiposControlador.Add(new { Valor = TipoControlador.PI_D, Descricao = "Controlador PI-D" });

            lbxTipoControlador.ValueMember = "Valor";
            lbxTipoControlador.DisplayMember = "Descricao";

            lbxTipoControlador.DataSource = tiposControlador;

            lbxTipoControlador.SelectedIndex = 0;
        }

        public DialogResult ExibirAba(TipoAba aba)
        {
            switch (aba)
            {
                case TipoAba.Planta:
                    tbcPrincipal.SelectedTab = abaPlanta;
                    break;
                case TipoAba.Entrada:
                    tbcPrincipal.SelectedTab = abaEntrada;
                    break;
                case TipoAba.Controlador1:
                    tbcPrincipal.SelectedTab = abaControlador;
                    break;
                default:
                    throw new ApplicationException("Tipo de aba inválido.");
            }

            return this.ShowDialog(formPrincipal);
        }

        private void btnOK_Click(object sender, EventArgs e)
        {
            try
            {
                ValidarCampos();

                ucConfigurarPlanta.MontarPlanta();
                MontarEntrada();
                MontarControlador();

                Global.Planta = ucConfigurarPlanta.Planta;
                Global.Entrada = entrada;
                Global.Controlador1 = controlador;

                this.DialogResult = System.Windows.Forms.DialogResult.OK;

                this.Hide();
            }
            catch (ApplicationException apex)
            {
                MessageBox.Show(apex.Message, "Erro", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        private void ValidarCampos()
        {
            ucConfigurarPlanta.ValidarCampos();
            ValidarCamposControlador();
            ValidarCamposEntrada();
        }

        private void ValidarCamposControlador()
        {
            int parseResultInt;
            double parseResultDouble;

            if (!int.TryParse(txtPeriodoControlador.Text, out parseResultInt))
            {
                throw new ApplicationException("Valor de período do controlador inválido.");
            }

            if (!double.TryParse(txtLimiteSeguranca.Text.Replace('.', ','), out parseResultDouble))
            {
                throw new ApplicationException("Valor de limite de segurança do controlador inválido.");
            }

            if (IsMalhaFechada())
            {
                if (TipoControlador.PadraoMF != (TipoControlador)lbxTipoControlador.SelectedValue &&
                    !double.TryParse(txtKp.Text.Replace('.', ','), out parseResultDouble))
                {
                    throw new ApplicationException("Valor de Kp inválido.");
                }

                if ((TipoControlador.PI == (TipoControlador)lbxTipoControlador.SelectedValue ||
                    TipoControlador.PID == (TipoControlador)lbxTipoControlador.SelectedValue ||
                    TipoControlador.PI_D == (TipoControlador)lbxTipoControlador.SelectedValue) &&
                    rbtKi.Checked && !double.TryParse(txtKi.Text.Replace('.', ','), out parseResultDouble))
                {
                    throw new ApplicationException("Valor de Ki inválido.");
                }

                if ((TipoControlador.PI == (TipoControlador)lbxTipoControlador.SelectedValue ||
                    TipoControlador.PID == (TipoControlador)lbxTipoControlador.SelectedValue ||
                    TipoControlador.PI_D == (TipoControlador)lbxTipoControlador.SelectedValue) &&
                    rbtTi.Checked && !double.TryParse(txtTi.Text.Replace('.', ','), out parseResultDouble))
                {
                    throw new ApplicationException("Valor de Ti inválido.");
                }

                if ((TipoControlador.PD == (TipoControlador)lbxTipoControlador.SelectedValue ||
                    TipoControlador.PID == (TipoControlador)lbxTipoControlador.SelectedValue ||
                    TipoControlador.PI_D == (TipoControlador)lbxTipoControlador.SelectedValue) &&
                    rbtKd.Checked && !double.TryParse(txtKd.Text.Replace('.', ','), out parseResultDouble))
                {
                    throw new ApplicationException("Valor de Kd inválido.");
                }

                if ((TipoControlador.PD == (TipoControlador)lbxTipoControlador.SelectedValue ||
                    TipoControlador.PID == (TipoControlador)lbxTipoControlador.SelectedValue ||
                    TipoControlador.PI_D == (TipoControlador)lbxTipoControlador.SelectedValue) &&
                    rbtTd.Checked && !double.TryParse(txtTd.Text.Replace('.', ','), out parseResultDouble))
                {
                    throw new ApplicationException("Valor de Td inválido.");
                }
            }
            else
            {

            }
        }

        private void ValidarCamposEntrada()
        {
            int parseResultInt;
            double parseResultDouble;

            if (IsMalhaFechada())
            {
                if (!double.TryParse(txtValorReferencia.Text.Replace('.', ','), out parseResultDouble))
                {
                    throw new ApplicationException("Valor de referência inválido.");
                }
            }
            else
            {
                if (!double.TryParse(txtAmplitudeEntrada.Text.Replace('.', ','), out parseResultDouble))
                {
                    throw new ApplicationException("Valor de amplitude de entrada inválido.");
                }

                if ((rbtEntradaOndaSenoidalMA.Checked ||
                    rbtEntradaOndaQuadradaMA.Checked ||
                    rbtEntradaOndaDenteSerraMA.Checked ||
                    rbtEntradaAleatoriaMA.Checked) && 
                    !int.TryParse(txtPeriodoEntrada.Text, out parseResultInt))
                {
                    throw new ApplicationException("Valor de período de entrada inválido.");
                }

                if ((rbtEntradaOndaSenoidalMA.Checked ||
                    rbtEntradaAleatoriaMA.Checked) &&
                    !double.TryParse(txtAnguloFaseEntrada.Text.Replace('.', ','), out parseResultDouble))
                {
                    throw new ApplicationException("Valor de ângulo de fase de entrada inválido.");
                }

                if ((rbtEntradaOndaSenoidalMA.Checked ||
                    rbtEntradaAleatoriaMA.Checked) &&
                    !double.TryParse(txtNivelDCEntrada.Text.Replace('.', ','), out parseResultDouble))
                {
                    throw new ApplicationException("Valor de nível DC de entrada inválido.");
                }
            }
        }

        private void MontarEntrada()
        {
            int sorteio = new Random().Next(1, 5);

            double amplitude = IsMalhaFechada() ? double.Parse(txtValorReferencia.Text.Replace('.', ',')) : double.Parse(txtAmplitudeEntrada.Text.Replace('.', ','));
            int periodo = int.Parse(txtPeriodoEntrada.Text);
            double anguloFase = double.Parse(txtAnguloFaseEntrada.Text.Replace('.', ','));
            double nivelDC = double.Parse(txtNivelDCEntrada.Text.Replace('.', ','));

            if (rbtEntradaDegrau.Checked || (rbtEntradaAleatoriaMA.Checked && sorteio == 1))
            {
                entrada = new EntradaDegrau(amplitude);
            }
            else if (rbtEntradaOndaSenoidalMA.Checked || (rbtEntradaAleatoriaMA.Checked && sorteio == 2))
            {
                entrada = new EntradaSenoidal(periodo, amplitude, anguloFase, nivelDC);
            }
            else if (rbtEntradaOndaQuadradaMA.Checked || (rbtEntradaAleatoriaMA.Checked && sorteio == 3))
            {
                entrada = new EntradaQuadrada(periodo, amplitude, anguloFase, nivelDC);
            }
            else if (rbtEntradaOndaDenteSerraMA.Checked || (rbtEntradaAleatoriaMA.Checked && sorteio == 4))
            {
                entrada = new EntradaDenteSerra(periodo, amplitude, anguloFase, nivelDC);
            }
            else
            {
                throw new ApplicationException("Tipo de entrada inválida.");
            }
        }

        private void MontarControlador()
        {
            int periodo = int.Parse(txtPeriodoControlador.Text);
            double limiteSeguranca = double.Parse(txtLimiteSeguranca.Text.Replace('.', ',')) / 100;
            
            if (Global.Controlador1 is ControladorMalhaFechada)
            {
                controladorMF = Global.Controlador1 as ControladorMalhaFechada;
            }
            else
            {
                controladorMA = Global.Controlador1 as ControladorMalhaAberta;
            }

            if (IsMalhaFechada())
            {
                double kp = 0;
                double ki = 0;
                double kd = 0;

                if (TipoControlador.PadraoMF != (TipoControlador)lbxTipoControlador.SelectedValue)
                {
                    kp = double.Parse(txtKp.Text.Replace('.', ','));
                }

                if (TipoControlador.PI == (TipoControlador)lbxTipoControlador.SelectedValue ||
                    TipoControlador.PID == (TipoControlador)lbxTipoControlador.SelectedValue ||
                    TipoControlador.PI_D == (TipoControlador)lbxTipoControlador.SelectedValue)
                {
                    ki = rbtKi.Checked ? double.Parse(txtKi.Text.Replace('.', ',')) : 1 / double.Parse(txtTi.Text.Replace('.', ','));
                }

                if (TipoControlador.PD == (TipoControlador)lbxTipoControlador.SelectedValue ||
                    TipoControlador.PID == (TipoControlador)lbxTipoControlador.SelectedValue ||
                    TipoControlador.PI_D == (TipoControlador)lbxTipoControlador.SelectedValue)
                {
                    kd = rbtKd.Checked ? double.Parse(txtKd.Text.Replace('.', ',')) : 1 / double.Parse(txtTd.Text.Replace('.', ','));
                }

                switch ((TipoControlador)lbxTipoControlador.SelectedValue)
                {
                    case TipoControlador.PadraoMF:
                        if (controladorMF is ControladorDefaultMalhaFechada)
                        {

                        }
                        else
                        {
                            controladorMF = new ControladorDefaultMalhaFechada(TipoPosicaoControlador.Unico);
                        }
                        break;
                    case TipoControlador.P:
                        if (controladorMF is ControladorP)
                        {
                            (controladorMF as ControladorP).SetGanho(kp);
                        }
                        else
                        {
                            controladorMF = new ControladorP(TipoPosicaoControlador.Unico, kp);
                        }
                        break;
                    case TipoControlador.PI:
                        if (controladorMF is ControladorPI)
                        {
                            (controladorMF as ControladorPI).SetGanho(kp, ki);
                        }
                        else
                        {
                            controladorMF = new ControladorPI(TipoPosicaoControlador.Unico, kp, ki, periodo);
                        }
                        break;
                    case TipoControlador.PD:
                        if (controladorMF is ControladorPD)
                        {
                            (controladorMF as ControladorPD).SetGanho(kp, kd);
                        }
                        else
                        {
                            controladorMF = new ControladorPD(TipoPosicaoControlador.Unico, kp, kd, periodo);
                        }
                        break;
                    case TipoControlador.PID:
                        if (controladorMF is ControladorPID)
                        {
                            (controladorMF as ControladorPID).SetGanho(kp, ki, kd);
                        }
                        else
                        {
                            controladorMF = new ControladorPID(TipoPosicaoControlador.Unico, kp, ki, kd, periodo);
                        }
                        break;
                    case TipoControlador.PI_D:
                        if (controladorMF is ControladorPI_D)
                        {
                            (controladorMF as ControladorPI_D).SetGanho(kp, ki, kd);
                        }
                        else
                        {
                            controladorMF = new ControladorPI_D(TipoPosicaoControlador.Unico, kp, ki, kd, periodo);
                        }
                        break;
                    default:
                        throw new ApplicationException("Tipo de controlador de malha fechada inválido.");
                }

                controladorMF.Referencia = entrada;

                controlador = controladorMF;
            }
            else
            {
                if (controladorMA == null)
                {
                    controladorMA = new ControladorDefaultMalhaAberta();
                }

                controladorMA.Entrada = entrada;

                controlador = controladorMA;
            }

            (controlador as AbstractControlador).Planta = ucConfigurarPlanta.Planta;
            (controlador as AbstractControlador).Periodo = periodo;
            (controlador as AbstractControlador).LimiteSeguranca = limiteSeguranca;
        }

        private Boolean IsMalhaFechada()
        {
            TipoControlador controladorSelecionado = (TipoControlador)lbxTipoControlador.SelectedValue;

            return controladorSelecionado != TipoControlador.PadraoMA;
        }

        private void rbtTipoEntrada_CheckedChanged(object sender, EventArgs e)
        {
            AtualizarEntrada();
        }

        private void AtualizarEntrada()
        {
            if (rbtEntradaDegrau.Checked)
            {
                if (!IsMalhaFechada())
                {
                    txtAmplitudeEntrada.Enabled = true;

                    txtValorReferencia.Enabled = false;
                    txtPeriodoEntrada.Enabled = false;
                    txtAnguloFaseEntrada.Enabled = false;
                    txtNivelDCEntrada.Enabled = false;
                }
                else
                {
                    txtValorReferencia.Enabled = true;

                    txtAmplitudeEntrada.Enabled = false;
                    txtPeriodoEntrada.Enabled = false;
                    txtAnguloFaseEntrada.Enabled = false;
                    txtNivelDCEntrada.Enabled = false;
                }
            }
            else if (rbtEntradaOndaSenoidalMA.Checked ||
                rbtEntradaAleatoriaMA.Checked)
            {
                txtAmplitudeEntrada.Enabled = true;

                txtValorReferencia.Enabled = false;
                txtPeriodoEntrada.Enabled = true;
                txtAnguloFaseEntrada.Enabled = true;
                txtNivelDCEntrada.Enabled = true;
            }
            else if (rbtEntradaOndaQuadradaMA.Checked ||
                rbtEntradaOndaDenteSerraMA.Checked)
            {
                txtAmplitudeEntrada.Enabled = true;

                txtValorReferencia.Enabled = false;
                txtPeriodoEntrada.Enabled = true;
                txtAnguloFaseEntrada.Enabled = false;
                txtNivelDCEntrada.Enabled = false;
            }
        }

        private void lbxTipoControlador_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (!IsMalhaFechada())
            {
                rbtEntradaOndaSenoidalMA.Enabled = true;
                rbtEntradaOndaQuadradaMA.Enabled = true;
                rbtEntradaOndaDenteSerraMA.Enabled = true;
                rbtEntradaAleatoriaMA.Enabled = true;
                gbxAcoes.Enabled = false;
            }
            else
            {
                rbtEntradaOndaSenoidalMA.Enabled = false;
                rbtEntradaOndaQuadradaMA.Enabled = false;
                rbtEntradaOndaDenteSerraMA.Enabled = false;
                rbtEntradaAleatoriaMA.Enabled = false;

                rbtEntradaDegrau.Checked = true;

                TipoControlador controlador = (TipoControlador)lbxTipoControlador.SelectedValue;

                switch (controlador)
                {
                    case TipoControlador.PadraoMF:
                        gbxAcoes.Enabled = false;
                        break;
                    case TipoControlador.P:
                        gbxAcoes.Enabled = true;

                        pnlAcaoProporcional.Enabled = true;
                        pnlAcaoIntegral.Enabled = false;
                        pnlAcaoDerivativa.Enabled = false;
                        break;
                    case TipoControlador.PI:
                        gbxAcoes.Enabled = true;

                        pnlAcaoProporcional.Enabled = true;
                        pnlAcaoIntegral.Enabled = true;
                        pnlAcaoDerivativa.Enabled = false;
                        break;
                    case TipoControlador.PD:
                        gbxAcoes.Enabled = true;

                        pnlAcaoProporcional.Enabled = true;
                        pnlAcaoIntegral.Enabled = false;
                        pnlAcaoDerivativa.Enabled = true;
                        break;
                    case TipoControlador.PID:
                    case TipoControlador.PI_D:
                        gbxAcoes.Enabled = true;

                        pnlAcaoProporcional.Enabled = true;
                        pnlAcaoIntegral.Enabled = true;
                        pnlAcaoDerivativa.Enabled = true;
                        break;
                    default:
                        throw new ApplicationException("Tipo de controlador de malha fechada inválido.");
                        break;
                }
            }

            AtualizarEntrada();
        }

        private void rbtAcaoIntegrativa_CheckedChanged(object sender, EventArgs e)
        {
            if (rbtKi.Checked)
            {
                txtKi.Enabled = true;
                txtTi.Enabled = false;

                rbtKd.Checked = true;

                Global.ConfiguraKi1 = true;
            }
            else
            {
                txtKi.Enabled = false;
                txtTi.Enabled = true;

                rbtTd.Checked = true;

                Global.ConfiguraKi1 = false;
            }
        }

        private void rbtAcaoDerivativa_CheckedChanged(object sender, EventArgs e)
        {
            if (rbtKd.Checked)
            {
                txtKd.Enabled = true;
                txtTd.Enabled = false;

                rbtKi.Checked = true;

                Global.ConfiguraKd1 = true;
            }
            else
            {
                txtKd.Enabled = false;
                txtTd.Enabled = true;

                rbtTi.Checked = true;

                Global.ConfiguraKd1 = false;
            }
        }

        public void AtualizarCampos()
        {
            AtualizarCamposEntrada();
            AtualizarCamposControlador();
        }

        private void AtualizarCamposEntrada()
        {
            if (Global.Controlador1 is ControladorMalhaFechada)
            {
                txtValorReferencia.Text = ((Global.Controlador1 as ControladorMalhaFechada).Referencia as EntradaDegrau).ValorAmplitude.ToString();
            }
            else
            {
                IEntrada entrada = (Global.Controlador1 as ControladorMalhaAberta).Entrada;

                if (entrada is EntradaDegrau)
                {
                    txtAmplitudeEntrada.Text = (entrada as EntradaDegrau).ValorAmplitude.ToString();
                }
                else if (entrada is EntradaPeriodica)
                {
                    txtAmplitudeEntrada.Text = (entrada as EntradaPeriodica).AmplitudeMaxima.ToString();
                }
                else
                {
                    throw new ApplicationException("Tipo de entrada inválida.");
                }
            }
        }

        public void AtualizarCamposControlador()
        {
            if (Global.Controlador1 is ControladorMalhaFechada)
            {
                if (Global.Controlador1 is ControladorDefaultMalhaFechada)
                {

                }
                else if (Global.Controlador1 is ControladorP)
                {
                    txtKp.Text = (Global.Controlador1 as ControladorP).Kp.ToString();
                }
                else if (Global.Controlador1 is ControladorPI)
                {
                    txtKp.Text = (Global.Controlador1 as ControladorPI).Kp.ToString();

                    if (Global.ConfiguraKi1)
                    {
                        rbtKi.Checked = true;
                        txtTi.Text = "";
                        txtKi.Text = (Global.Controlador1 as ControladorPI).Ki.ToString();
                    }
                    else
                    {
                        rbtTi.Checked = true;
                        txtKi.Text = "";
                        txtTi.Text = (1 / (Global.Controlador1 as ControladorPI).Ki).ToString();
                    }
                }
                else if (Global.Controlador1 is ControladorPD)
                {
                    txtKp.Text = (Global.Controlador1 as ControladorPD).Kp.ToString();
                    
                    if (Global.ConfiguraKd1)
                    {
                        rbtKd.Checked = true;
                        txtTd.Text = "";
                        txtKd.Text = (Global.Controlador1 as ControladorPD).Kd.ToString();
                    }
                    else
                    {
                        rbtTd.Checked = true;
                        txtKd.Text = "";
                        txtTd.Text = (1 / (Global.Controlador1 as ControladorPD).Kd).ToString();
                    }
                }
                else if (Global.Controlador1 is ControladorPID)
                {
                    txtKp.Text = (Global.Controlador1 as ControladorPID).Kp.ToString();

                    if (Global.ConfiguraKi1)
                    {
                        rbtKi.Checked = true;
                        txtTi.Text = "";
                        txtKi.Text = (Global.Controlador1 as ControladorPID).Ki.ToString();
                    }
                    else
                    {
                        rbtTi.Checked = true;
                        txtKi.Text = "";
                        txtTi.Text = (1 / (Global.Controlador1 as ControladorPID).Ki).ToString();
                    }

                    if (Global.ConfiguraKd1)
                    {
                        rbtKd.Checked = true;
                        txtTd.Text = "";
                        txtKd.Text = (Global.Controlador1 as ControladorPID).Kd.ToString();
                    }
                    else
                    {
                        rbtTd.Checked = true;
                        txtKd.Text = "";
                        txtTd.Text = (1 / (Global.Controlador1 as ControladorPID).Kd).ToString();
                    }
                }
                else if (Global.Controlador1 is ControladorPI_D)
                {
                    txtKp.Text = (Global.Controlador1 as ControladorPI_D).Kp.ToString();

                    if (Global.ConfiguraKi1)
                    {
                        rbtKi.Checked = true;
                        txtTi.Text = "";
                        txtKi.Text = (Global.Controlador1 as ControladorPI_D).Ki.ToString();
                    }
                    else
                    {
                        rbtTi.Checked = true;
                        txtKi.Text = "";
                        txtTi.Text = (1 / (Global.Controlador1 as ControladorPI_D).Ki).ToString();
                    }

                    if (Global.ConfiguraKd1)
                    {
                        rbtKd.Checked = true;
                        txtTd.Text = "";
                        txtKd.Text = (Global.Controlador1 as ControladorPI_D).Kd.ToString();
                    }
                    else
                    {
                        rbtTd.Checked = true;
                        txtKd.Text = "";
                        txtTd.Text = (1 / (Global.Controlador1 as ControladorPI_D).Kd).ToString();
                    }
                }
                else
                {
                    throw new ApplicationException("Tipo de controlador de malha fechada inválido.");
                }
            }
            else
            {

            }
        }
    }
}
